/*
* EP-Tracing System : a tool to trace mountain hike.           .kNNx
* Copyright (C) 2009  Raffaello Brondi                         'KNNNk
*                                                             ,XNNNl
* This program is free software:                             ,XNN0'
* you can redistribute it and/or modify                     ,XNNx.
* it under the terms of the                                'XNNl
* GNU General Public License                              .KNN:                     ..
* as published by                                        .0NNo                    .ONNO.
* the Free Software Foundation,                          xNNN.  :dkd,            .KNNNN;
* either version 3 of the License, or                   :NNNK ;XNNNNNo          ,KNNNX:
* (at your option) any later version.                   xNNNNcXNNNNNNk         cNNNNx.
*                                                       ,XNNNNNNNNNNX'       .xNNNK;
*                                                        .lKNNNNNNNK'       :KNNNo
*                                                          ;kNNNNNKxl;'.'l0NNNk.
* This program is distributed in                          .'  .:xXNNNNNNNNNNNO,
* the hope that it will be useful,                       :NNXd'   ,oONNNNNNk,
* but WITHOUT ANY WARRANTY;                              xNNNNN0c.    .;;,.
* without even the implied warranty of                   kNNNNNNNXd'
* MERCHANTABILITY or                                     xNNNNNNNNNNOc.
* FITNESS FOR A PARTICULAR PURPOSE.                      xNNNNNNNNNNNNXd.
* See the GNU General Public License                     ONNNN0.,o0NNNNNNl
* for more details.                                      0NNNNd    kNNNNNX.
*                                                        KNNNNl   oNNNNNXc
*                                                       .XNNNN:  dNNNNNx.
* You should have received a copy                       .XNNNN; lNNNNO'
* of the GNU General Public License                     .XNNNN; 'dxo'
* along with this program.                              .XNNNN;
* If not, see <http://www.gnu.org/licenses/>.            0NNNN:
*                                                        kNNNNc
*                                                        oNNNNd
*                                                        ;NNNN0
* Contact: rbrondi@gmail.com                             .XNNNN;
*                                                         kNNNNd
*                                                         .coo:.
*/

package EP.GPS.Path;

import EP.FileSystemManager;

/**
 *
 * @author Raffaello Brondi
 */
public class SwappablePathBuffer {

    private final byte SWAP_UNIT0 = 0;
    private final byte SWAP_UNIT1 = 1;
    private PathPoint[][] swapBuffers;
    private int size;
    private byte swapUnit;
    private int insertionIndex;
    private Object swapMutex = new Object();
    private boolean consumerRunning = false;
    private boolean empty;

    public SwappablePathBuffer(int size) {
        this.empty = true;
        this.insertionIndex = 0;
        this.swapUnit = SWAP_UNIT0;
        this.size = size;
        this.swapBuffers = new PathPoint[2][size];
        this.swapBuffers[SWAP_UNIT0] = new PathPoint[size];
        this.swapBuffers[SWAP_UNIT1] = new PathPoint[size];
    }

    public int size() {
        return this.size;
    }

    protected PathPoint elementAt(int index) {
        return this.swapBuffers[((this.swapUnit + 1) % 2)][index];
    }

    public synchronized void put(PathPoint p) {
        if (this.insertionIndex == this.size) {
            System.out.println("buffer full");
            if (this.consumerRunning) {
                try {
                    System.out.println("consumer is sill running..waiting!");
                    wait();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
            System.out.println("consumer is not running!Start swap");
            this.swap();
            this.insertionIndex = 0;
        }
        //System.out.println("p added to buffer " + this.swapUnit);
        if(this.empty)
            this.empty = false;
        this.swapBuffers[this.swapUnit][this.insertionIndex] = p;
        this.insertionIndex++;

    }

    public synchronized void flush(String closure) {
        //System.out.println("\nFlushing the buffer");
        if (this.insertionIndex == 0) {
            return;
        }

        if (this.consumerRunning) {
            try {
                System.out.println("consumer is sill running..waiting!");
                wait();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        System.out.println("consumer is not running!Start flush");
        synchronized (this.swapMutex) {
            StringBuffer stb = new StringBuffer();
            for (int i = 0; i < this.insertionIndex; i++) {
                stb.append((PathPoint) this.swapBuffers[this.swapUnit][i]);
                if (i < this.insertionIndex - 1) {
                    stb.append(",");
                }
            }
            FileSystemManager.getInstance().print(stb.toString() + closure);
        }
        this.insertionIndex = 0;

    }

    private void swap() {

        synchronized (this.swapMutex) {
            this.swapIndex();
            this.consumerRunning = true;
            new PathConsumer(this).start();
        }
    }

    protected synchronized void swapFinished() {
        //synchronized (this.swapMutex) {

        this.consumerRunning = false;
        System.out.println("Swap finished!notify all");
        notifyAll();
        //}
    }

    public synchronized PathPoint getLast() {
        if (this.empty) {
            return null;
        } else if (this.insertionIndex == 0) {
            return this.swapBuffers[((this.swapUnit + 1) % 2)][this.size - 1];
        } else {
            return this.swapBuffers[this.swapUnit][this.insertionIndex - 1];
        }
    }

    private void swapIndex() {
        this.swapUnit = (byte) ((this.swapUnit + 1) % 2);
    }

    protected PathPoint[] getBuffer() {
        return this.swapBuffers[(this.swapUnit + 1) % 2];
    }
}
